home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc Source Code / Storage / Bento / CMDoc.cpp < prev    next >
Encoding:
Text File  |  1996-04-22  |  45.6 KB  |  1,608 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        CMDoc.cpp
  3.  
  4.     Contains:    Implementation for CMDoc class.
  5.  
  6.     Owned by:    Vincent Lo
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <2>     3/15/96    DM        1295410: create list iterators on stack
  13.                                     (avoid mem thrash during purge)
  14.         <54>    10/24/95    jpa        1293441: DM/VL: Bento memory reserve &
  15.                                     fatal container err & don't throw in
  16.                                     Release.
  17.         <53>    10/20/95    VL        1293256: Changed
  18.                                     kODErrBentoInvalidVersionList to
  19.                                     kODErrDraftDoesNotExist.
  20.         <52>    10/13/95    EL        1287340: Use standard ISO prefix
  21.         <51>     10/8/95    TJ        Fixes Recomended by Refball
  22.         <50>     10/3/95    TJ        Added Includes so it compiles
  23.         <49>     10/3/95    TJ        Changes done by RefBall Team
  24.         <48>     9/29/95    TJ        Made Changes for MAC SOM
  25.         <47>      9/8/95    VL        1282012: Replaced kODErrDraftNotExists with
  26.                                     kODErrDraftDoesNotExist.
  27.         <46>      9/8/95    TÇ        1281096 FB2:Many constants in ODTypesB
  28.                                     without kOD prefix!
  29.         <45>      9/7/95    EL        1281410: Window for draft just above a
  30.                                     deleted draft will not be automatically
  31.                                     closed when that draft is deleted.
  32.         <44>     8/30/95    EL        1270290: Do not close and open the draft in
  33.                                     SaveToPrev and Collapse draft if draft is
  34.                                     not top draft and hence read only.
  35.         <43>     8/21/95    VL        1278330, 1278315: Error code cleanup.
  36.         <42>     8/18/95    NP        1274946: add kODErrInvalidPersistentFormat
  37.         <41>     8/16/95    NP        1274946: ErrorDef.idl problems. Add include
  38.                                     file.
  39.         <40>     8/12/95    TÇ        1276806 Optimization: use kODFalse instead
  40.                                     of kODTrue in comparisons
  41.         <39>      8/8/95    EL        #1273589: version list is not collapsed
  42.                                     when document is closed.
  43.         <38>      8/3/95    RR        #1257260: Collapse B classes. Remove
  44.                                     somInit methods. Don't call IsInitialized
  45.                                     or SubclassResponsibility
  46.         <37>     7/21/95    VL        1270320: Removed internal field _fName.
  47.         <36>     6/28/95    RR        1242642 BB Mostly ref counting. RemoveDraft
  48.                                     releases draft before deleting it
  49.         <35>     6/20/95    VL        1259397: Release Draft after getting its id
  50.                                     in GetDraftGut.
  51.         <34>     5/26/95    VL        1251403: Multithreading naming support.
  52.         <33>     5/25/95    jpa        Fixed usage of ODDebug. [1253321]
  53.         <32>     5/18/95    CC        1238898: Add destFrame argument to
  54.                                     BeginClone call.
  55.         <31>     5/18/95    EL        1249941: Set container dirty flag when
  56.                                     drafts changed.
  57.         <30>     4/25/95    VL        1210982: Removed 5$.
  58.         <29>      4/7/95    EL        1225905: Call SetModDate when save to prev.
  59.         <28>     3/31/95    EL        1234685: If top draft embedded container
  60.                                     has not been saved don't write it in the
  61.                                     version list. Don't externalize version
  62.                                     list except before flush or close.
  63.         <27>     3/29/95    DM        make standard format little endian
  64.         <26>     3/24/95    EL        1209355: Cut down on version list
  65.                                     externalization. Flush file container in
  66.                                     SaveToAPrevDraft.
  67.         <25>     3/23/95    VL        1230357: Implemented Purge. 1228003: Added
  68.                                     debug code for versionlist.
  69.         <24>      3/9/95    VL        1220320: Moved public error codes from
  70.                                     Bento to ErrorDef.idl.
  71.         <23>     2/17/95    EL        1182275: Collapse version list before
  72.                                     closing embedded container so we know if
  73.                                     there is a new draft.
  74.         <22>     2/13/95    TÇ        1219963: Document:AcquireDraft should not bump
  75.                                     refcount if kPosSame and release==true
  76.         <21>     1/31/95    EL        1195846: revert file if there is no real
  77.                                     change.
  78.         <20>     1/26/95    eeh        1214080: OpenDoc really uses kODMacIText,
  79.                                     not kODIntlText.
  80.         <19>     1/25/95    jpa        Include StdExts.xh
  81.         <18>     1/11/95    VL        1185688: Made storage more robust in terms
  82.                                     of error handling. Also did some code
  83.                                     review cleanup.
  84.         <17>    11/14/94    VL        1155887: Changed AcquireDraft to handle new
  85.                                     posCode for top draft.
  86.         <16>    10/19/94    VL        1155857: Added ODDebug_Drafts for debugging
  87.                                     "Cannot create more than 10 drafts"
  88.                                     problem.
  89.         <15>     9/29/94    RA        1189812: Mods for 68K build.
  90.         <14>     9/23/94    VL        1184272: ContainerID is now a sequence of
  91.                                     octets. 1184166: DocumentName is ODIText
  92.                                     now.
  93.         <13>      9/6/94    VL        1184154: Include StorageU.xh.
  94.         <12>      9/6/94    VL        1184154: Removed include file also.
  95.         <11>      9/6/94    VL        1184154: Removed AcquireDocumentProperties.
  96.         <10>      9/5/94    VL        1184871: Used Renew to remove dependency on
  97.                                     default heap.
  98.          <9>     8/31/94    TÇ        #1183129, #1183116, #1183119, #1183111:
  99.                                     Lots of ErrorCode cleanup.
  100.          <8>     8/31/94    VL        No code change. Fixed comments in <7>.
  101.          <7>     8/31/94    VL        1161158, 1106013: Commented out code which
  102.                                     does checking on embedded container's use
  103.                                     mode in AcquireDraft. This should avoid a
  104.                                     crashing bug when the embedded container is
  105.                                     kODNULL. Also, fixed GetName to make it
  106.                                     return kODNULL if the document doesn't have a name.
  107.          <6>     8/26/94    VL        1183174: Use updated cloning APIs.
  108.          <5>     8/16/94    TÇ        #1180922  Remove more obsolete types from
  109.                                     StdTypes.idl.  Localized kODVersionList to
  110.                                     this file.
  111.          <4>      8/3/94    VL        1153123: Storage to ODStor.
  112.          <3>     7/14/94    VL        Check return value for kODNULL before
  113.                                     calling GetUseMode in AcquireDraftGut.
  114.          <2>     7/11/94    VL        Added Exists.
  115.          <1>      7/5/94    VL        first checked in
  116.  
  117.     To Do:
  118.     In Progress:
  119.         
  120. */
  121.  
  122. #define CMDocument_Class_Source
  123. #define VARIABLE_MACROS
  124. #include <CMDoc.xih>
  125.  
  126. #ifndef SOM_ODContainer_xh
  127. #include <ODCtr.xh>
  128. #endif
  129.  
  130. #ifndef SOM_ODStorageUnit_xh
  131. #include <StorageU.xh>
  132. #endif
  133.  
  134. #ifndef _EXCEPT_
  135. #include "Except.h"
  136. #endif
  137.  
  138. #ifndef _TEMPOBJ_
  139. #include "TempObj.h"
  140. #endif
  141.  
  142. #ifndef _FLIPEND_
  143. #include "FlipEnd.h"
  144. #endif
  145.  
  146. #ifndef SOM_ODEmbeddedContainer_xh
  147. #include <EmbedCtr.xh>
  148. #endif
  149.  
  150. #ifndef SOM_CMDraft_xh
  151. #include <CMDraft.xh>
  152. #endif
  153.  
  154. #ifndef SOM_ODSession_xh
  155. #include <ODSessn.xh>
  156. #endif
  157.  
  158. #ifndef __STRING__
  159. #include <string.h>        // For strlen, strcpy....
  160. #endif
  161.  
  162. #ifndef _INDHDR_
  163. #include "IndHdr.h"            // For Embedded Property and Type names
  164. #endif
  165.  
  166. #ifndef _CMCTR_
  167. #include "CMCtr.xh"            // Just for getting fContainer
  168. #endif
  169.  
  170. #ifndef _DOCPRIV_
  171. #include "DocPriv.h"
  172. #endif
  173.  
  174. #ifndef _ISOSTR_
  175. #include "ISOStr.h"
  176. #endif
  177.  
  178. #ifndef SOM_Module_OpenDoc_StdProps_defined
  179. #include <StdProps.xh>
  180. #endif
  181.  
  182. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  183. #include <StdTypes.xh>
  184. #endif
  185.  
  186. #ifndef _ODMEMORY_
  187. #include "ODMemory.h"
  188. #endif
  189.  
  190. #ifndef _ODNEW_
  191. #include "ODNew.h"
  192. #endif
  193.  
  194. #ifndef _BENTODEF_
  195. #include "BentoDef.h"
  196. #endif
  197.  
  198. #ifndef _ODDEBUG_
  199. #include <ODDebug.h>
  200. #endif
  201.  
  202. #ifndef _ITEXT_
  203. #include <IText.h>
  204. #endif
  205.  
  206. #ifndef _UTILERRS_
  207. #include "UtilErrs.h"
  208. #endif
  209.  
  210. #ifndef __TIME_H__
  211. #include <Time.h>
  212. #endif
  213.  
  214. #ifndef _SESSHDR_
  215. #include "SessHdr.h"
  216. #endif
  217.  
  218. #pragma segment CMDocument
  219.  
  220. //==============================================================================
  221. // Constants
  222. //==============================================================================
  223.  
  224. // Private ISO Strings
  225. const     ODPropertyName    kODDocumentProperties    = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:Bento Container Suite:Property:DocumentProperties";
  226. const    ODValueType        kODVersionList             = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:Bento Container Suite:Type:CMVersionList";
  227.  
  228. // For debugging
  229.  
  230. #if ODDebug
  231. // #define ODDebug_Drafts 1
  232. // #define ODDebug_DebugRefCount    1
  233. #endif
  234.  
  235. //==============================================================================
  236. // Function Prototype
  237. //==============================================================================
  238.  
  239. static CMDraft* NewCMDraft(ODMemoryHeapID heapID);
  240. static CMObject AcquireDocumentPropertiesObject(CMContainer container);
  241.  
  242. // The following two functions need to be filled in when we are moving to a 
  243. // real multithread system.
  244.  
  245. #define EnableInterrupt()
  246. #define DisableInterrupt()
  247.  
  248.  
  249. // For debugging
  250.  
  251. #ifdef DebugStorage
  252.  
  253. #define MyDebugStr(s) do {somPrintf(s);} while (0)
  254. #define MyDebug1Str(f,p1) do {somPrintf(f, p1);} while (0)
  255. #define MyDebug2Str(f,p1,p2) do {somPrintf(f, p1, p2);} while (0)
  256. #define MyDebug3Str(f,p1,p2,p3) do {somPrintf(f, p1, p2,p3);} while (0)
  257.  
  258. #else
  259.  
  260. #define MyDebugStr(s)
  261. #define MyDebug1Str(f,p1)
  262. #define MyDebug2Str(f,p1,p2)
  263. #define MyDebug3Str(f,p1,p2,p3)
  264.  
  265. #endif
  266.  
  267. #if ODDebug_Drafts
  268.  
  269. #ifndef _MEMDEBG_
  270. #include <MemDebg.h>
  271. #endif
  272.  
  273. static void PrintDrafts(Environment* ev, DraftList* drafts, char* string);
  274. static void PrintHeapInfo();
  275. #endif
  276.  
  277.  
  278. //==============================================================================
  279. // CMDocument
  280. //==============================================================================
  281.  
  282. //------------------------------------------------------------------------------
  283. // CMDocument: GetCMVersionList
  284. //------------------------------------------------------------------------------
  285.  
  286. SOM_Scope CMValue  SOMLINK CMDocumentGetCMVersionList(CMDocument *somSelf, Environment *ev)
  287. {
  288.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  289.     CMDocumentMethodDebug("CMDocument","CMDocumentGetCMVersionList");
  290.  
  291.     SOM_CATCH return kODNULL;
  292.     
  293.     CMContainer cmContainer = _fContainer->GetCMContainer(ev);
  294.     ODSessionMustHaveCMAllocReserve(cmContainer);
  295.     
  296.     CMProperty        versionListProp;
  297.     CMObject        versionListObj;
  298.     CMValue            versionList = kODNULL;
  299.     
  300.     if ((versionListProp = CMRegisterProperty(cmContainer, kODPropVersionList)) == kODNULL)
  301.         THROW(kODErrBentoInvalidProperty);
  302.         
  303.     versionListObj = CMGetNextObjectWithProperty(cmContainer, kODNULL, versionListProp);
  304.     
  305.     if (versionListObj != kODNULL)
  306.         versionList = CMGetNextValue(versionListObj, versionListProp, kODNULL);
  307.  
  308.     ODSessionRestoreCMAllocReserve(cmContainer);
  309.     return versionList;
  310. }
  311.  
  312. //------------------------------------------------------------------------------
  313. // CMDocument: AcquireDraftGut
  314. //------------------------------------------------------------------------------
  315.  
  316. SOM_Scope CMDraft*  SOMLINK CMDocumentAcquireDraftGut(CMDocument *somSelf, Environment *ev,
  317.         VersionList* versionList,
  318.         ODDraftPermissions perms,
  319.         ODDraftID id,
  320.         CMDraft* draft,
  321.         ODPositionCode posCode,
  322.         ODBoolean release)
  323. {
  324.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  325.     CMDocumentMethodDebug("CMDocument","CMDocumentAcquireDraftGut");
  326.  
  327.     SOM_CATCH    return kODNULL;
  328.  
  329. #if ODDebug_Drafts
  330.     somPrintf("**** Entering AcquireDraftGut: id %d draft %x posCode %d release %d\n", id, draft, posCode, release);
  331.     PrintDrafts(ev, _fDrafts, "**** Entering AcquireDraftGut");
  332.     somSelf->GetVersionList(ev)->Print(">>> Entering AcquireDraftGut");
  333. #endif
  334.  
  335.     CMDraft*                fromDraft = (CMDraft*) draft;
  336.     CMDraft*                newDraft = kODNULL;    
  337.     ODDraftID                latestDraftID;
  338.     ODDraftID                fromDraftID;
  339.     ODDraftID                prevDraftID;
  340.     ODDraftID                nextDraftID;
  341.  
  342.     if (id != 0) {
  343.         if ((newDraft = _fDrafts->Get(id)) != kODNULL) {
  344.             if ((perms == kODDPReadOnly) ||
  345.                 (newDraft->GetPermissions(ev) == kODDPExclusiveWrite)) {
  346.                 newDraft->Acquire(ev);
  347.                 MyDebugStr("**** AcquireDraft: Acquire only.\n");
  348.             }
  349.             else
  350.                 THROW(kODErrInvalidPermissions);
  351.         }
  352.         else if ((newDraft = _fReleasedDrafts->Get(id)) != kODNULL) {
  353.             if (perms == kODDPExclusiveWrite) {
  354.                 if (newDraft->GetPermissions(ev) == kODDPReadOnly) {
  355.                         latestDraftID = versionList->GetLatestDraftID();
  356.                         if (versionList->IsAbove(latestDraftID, id) != kODFalse)
  357.                             THROW(kODErrInvalidPermissions);
  358.                         MyDebugStr("**** AcquireDraft: From ReadOnly to ExclusiveWrite.\n");
  359.                 }
  360.             }
  361.             newDraft->Reinitialize(ev, perms);
  362.             _fReleasedDrafts->Remove(id);
  363.             _fDrafts->Add(id, newDraft);
  364.             newDraft->Acquire(ev);
  365.             MyDebugStr("**** AcquireDraft: Back from the _fReleasedDrafts pile.\n");
  366.         }
  367.         else {                
  368.             newDraft = NewCMDraft(somSelf->GetHeap(ev));
  369.             newDraft->InitDraft(ev, somSelf, id, perms);
  370.             
  371.             _fDrafts->Add(id, newDraft);
  372.     
  373.             MyDebug3Str("**** id %d draft %x perms %d\n", id, newDraft, newDraft->GetPermissions(ev));
  374.         }    
  375.     }
  376.     else {
  377.         if ((posCode != kODPosTop) && (fromDraft == kODNULL)) {
  378.             THROW(kODErrInvalidDraftID);
  379.         }
  380.         switch (posCode) {
  381.             case kODPosTop:
  382.                 if (fromDraft != kODNULL)
  383.                     THROW(kODErrInvalidDraftID);
  384.                 nextDraftID = versionList->GetLatestDraftID();
  385.                 newDraft = somSelf->AcquireDraftGut(ev, versionList,
  386.                                     perms,
  387.                                     nextDraftID,
  388.                                     kODNULL,
  389.                                     kODPosUndefined,
  390.                                     kODFalse);
  391.             break;
  392.             case kODPosSame:
  393.                 if (fromDraft->GetPermissions(ev) == perms) {
  394.                     if (release == kODFalse)
  395.                         fromDraft->Acquire(ev);
  396.                     newDraft = fromDraft;
  397.                 }
  398.                 else {
  399.                     if (fromDraft->GetRefCount(ev) != 1)
  400.                         THROW(kODErrRefCountNotEqualOne);
  401.                     if (release == kODFalse)
  402.                         THROW(kODErrCannotChangePermissions);
  403.                     fromDraftID = fromDraft->GetID(ev);
  404.                     fromDraft->Release(ev);
  405.                     newDraft = somSelf->AcquireDraftGut(ev, versionList,
  406.                                                 perms,
  407.                                                 fromDraftID,
  408.                                                 kODNULL,
  409.                                                 kODPosUndefined,
  410.                                                 kODFalse);
  411.                 }
  412.             break;
  413.             case kODPosFirstBelow:
  414.             case kODPosLastBelow:
  415.                 fromDraftID = fromDraft->GetID(ev);
  416.                 prevDraftID = versionList->GetPreviousDraftID(fromDraftID);
  417.                 if (release != kODFalse)
  418.                     fromDraft->Release(ev);
  419.                 newDraft = somSelf->AcquireDraftGut(ev, versionList,
  420.                                             perms,
  421.                                             prevDraftID,
  422.                                             kODNULL,
  423.                                             kODPosUndefined,
  424.                                             kODFalse);
  425.             break;
  426.             case kODPosFirstAbove:
  427.             case kODPosLastAbove:
  428.                 fromDraftID = fromDraft->GetID(ev);
  429.                 nextDraftID = versionList->GetNextDraftID(fromDraftID);
  430.                 if (release != kODFalse)
  431.                     fromDraft->Release(ev);
  432.                 newDraft = somSelf->AcquireDraftGut(ev, versionList,
  433.                                             perms,
  434.                                             nextDraftID,
  435.                                             kODNULL,
  436.                                             kODPosUndefined,
  437.                                             kODFalse);
  438.                 break;
  439.             case kODPosUndefined:
  440.             case kODPosAll:
  441.             case kODPosFirstSib:
  442.             case kODPosLastSib:
  443.             case kODPosNextSib:
  444.             case kODPosPrevSib:
  445.             default:
  446.                 THROW(kODErrUnsupportedPosCode);
  447.             break;
  448.         }
  449.     }
  450.     
  451. #if ODDebug_Drafts
  452.     PrintDrafts(ev, _fDrafts, "**** Exiting AcquireDraftGut");
  453.     somSelf->GetVersionList(ev)->Print(">>> Exiting AcquireDraftGut");
  454. #endif
  455.  
  456.     return newDraft;
  457. }
  458.  
  459. //------------------------------------------------------------------------------
  460. // CMDocument: ~CMDocument
  461. //------------------------------------------------------------------------------
  462.  
  463. SOM_Scope void  SOMLINK CMDocumentsomUninit(CMDocument *somSelf)
  464. {
  465.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  466.     CMDocumentMethodDebug("CMDocument","CMDocumentsomUninit");
  467.  
  468.     FN_CATCH return;
  469.     
  470.     Environment*    ev = somGetGlobalEnvironment();
  471.     
  472.     DraftListIterator iter(_fDrafts);
  473.     iter.Initialize();
  474.     
  475.     DraftListIterator releasedDraftsIter(_fReleasedDrafts);
  476.     releasedDraftsIter.Initialize();
  477.     
  478.     CMDraft*            draft;
  479.  
  480. #if ODDebug_DebugRefCount
  481.     if (somSelf->GetRefCount(ev) != 0)
  482.         DebugStr("\pRefCount of Document is not 0 at uninit.");
  483.     somPrintf("~CMDocument %x RefCount %d\n", somSelf, somSelf->GetRefCount(ev));
  484. #endif
  485.  
  486.     draft = iter.Last();
  487.     while (draft != kODNULL) {
  488.         delete draft;
  489.         draft = iter.Previous();
  490.     }
  491.         
  492.     draft = releasedDraftsIter.Last();
  493.     while (draft != kODNULL) {
  494.         delete draft;
  495.         draft = releasedDraftsIter.Previous();
  496.     }
  497.         
  498.     // delete iter;
  499.     // delete releasedDraftsIter;
  500.     
  501.     delete _fVersions;
  502.     delete _fDrafts;
  503.     delete _fReleasedDrafts;
  504.     
  505.     parent_somUninit(somSelf);
  506.  
  507. }
  508.  
  509. //------------------------------------------------------------------------------
  510. // CMDocument: Purge
  511. //------------------------------------------------------------------------------
  512.  
  513. SOM_Scope ODSize  SOMLINK CMDocumentPurge(CMDocument *somSelf, Environment *ev,
  514.         ODSize size)
  515. {
  516.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  517.     CMDocumentMethodDebug("CMDocument","CMDocumentPurge");
  518.   
  519.     ODSize purgedSize = 0; ODVolatile( purgedSize );
  520.          
  521.     SOM_TRY
  522.         DraftListIterator draftList(_fDrafts);
  523.         draftList.Initialize();
  524.         CMDraft* draft = draftList.Last();
  525.         while (draft != kODNULL) {
  526.             TRY
  527.                 purgedSize += draft->Purge(ev, size-purgedSize);
  528.             CATCH_ALL
  529.             ENDTRY
  530.             draft = draftList.Previous();
  531.         }
  532.     // delete draftList;
  533.     
  534.         purgedSize += parent_Purge(somSelf, ev, size);
  535.     SOM_CATCH_ALL
  536.         WARN("Error %ld trying to purge in CMDocumentPurge",ErrorCode());
  537.         SetErrorCode(kODNoError);        // Eat the exception; Purge should not 
  538.                                         // propagate it because clients function
  539.                                         // fine whether memory was purged or not.
  540.     SOM_ENDTRY
  541.  
  542.     return purgedSize;
  543. }
  544.  
  545. //------------------------------------------------------------------------------
  546. // CMDocument: Acquire
  547. //------------------------------------------------------------------------------
  548.  
  549. SOM_Scope void  SOMLINK CMDocumentAcquire(CMDocument *somSelf, Environment *ev)
  550. {
  551. //  CMDocumentData *somThis = CMDocumentGetData(somSelf);
  552.     CMDocumentMethodDebug("CMDocument","CMDocumentAcquire");
  553.  
  554.     parent_Acquire(somSelf,ev);
  555. }
  556.  
  557. //------------------------------------------------------------------------------
  558. // CMDocument: Release
  559. //------------------------------------------------------------------------------
  560.  
  561. SOM_Scope void  SOMLINK CMDocumentRelease(CMDocument *somSelf, Environment *ev)
  562. {
  563.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  564.     CMDocumentMethodDebug("CMDocument","CMDocumentRelease");
  565.  
  566.     SOM_TRY
  567.     
  568. #if TestFlushContainer
  569.         if (_fContainer->GetDirtyFlag(ev) != kODFalse)
  570.             somSelf->ExternalizeVersionList(ev, kODFalse);
  571. #endif
  572.  
  573.         parent_Release(somSelf,ev);
  574.         if (somSelf->GetRefCount(ev) == 0) {
  575.             _fContainer->ReleaseDocument(ev, somSelf);
  576.         }
  577.         
  578.     SOM_CATCH_ALL
  579.         
  580.         ODError err = ErrorCode();
  581.  
  582.         WARN("Error occurred in ODDocument::Release: %d %s", err, ErrorMessage() ?ErrorMessage() :"");
  583.  
  584.         if (err == kODErrBentoErr)
  585.             SetErrorCode(kODErrUndefined);
  586.         else if (err != kODErrUndefined)
  587.             SetErrorCode(kODNoError);
  588.         
  589.     ENDTRY
  590. }
  591.  
  592. //------------------------------------------------------------------------------
  593. // CMDocument: AcquireContainer
  594. //------------------------------------------------------------------------------
  595.  
  596. SOM_Scope ODContainer*  SOMLINK CMDocumentGetContainer(CMDocument *somSelf, Environment *ev)
  597. {
  598.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  599.     CMDocumentMethodDebug("CMDocument","CMDocumentGetContainer");
  600.  
  601.     return (ODContainer*) _fContainer;
  602. }
  603.  
  604. //------------------------------------------------------------------------------
  605. // CMDocument: GetID
  606. //------------------------------------------------------------------------------
  607.  
  608. SOM_Scope ODDocumentID  SOMLINK CMDocumentGetID(CMDocument *somSelf, Environment *ev)
  609. {
  610.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  611.     CMDocumentMethodDebug("CMDocument","CMDocumentGetID");
  612.  
  613.     return _fID;
  614. }
  615.  
  616. //------------------------------------------------------------------------------
  617. // CMDocument: GetName
  618. //------------------------------------------------------------------------------
  619.  
  620. SOM_Scope ODDocumentName SOMLINK CMDocumentGetName(CMDocument *somSelf, Environment *ev)
  621. {    
  622.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  623.     CMDocumentMethodDebug("CMDocument","CMDocumentGetName");
  624.     
  625.     ODDocumentName* name = kODNULL;
  626.  
  627.     SOM_TRY
  628.     
  629.     CMContainer cmContainer = _fContainer->GetCMContainer(ev);
  630.     ODSessionMustHaveCMAllocReserve(cmContainer);
  631.  
  632.     CMObject    cmObject = AcquireDocumentPropertiesObject(cmContainer);
  633.     ASSERTM(cmObject, kODErrNoDocumentProperties, "No Document Properties Object.");
  634.     
  635.     CMProperty    cmProp = CMRegisterProperty(cmContainer, kODPropDocumentName);
  636.     CMType        cmType = CMRegisterType(cmContainer, kODMacIText);
  637.     CMValue        cmValue = CMUseValue(cmObject, cmProp, cmType);
  638.     
  639.     if (cmValue != kODNULL) {
  640.         ODITextFormat stdFormat;
  641.         CMReadValueData(cmValue, &stdFormat, 0, sizeof(ODITextFormat));
  642.         ODITextFormat format = ConvertODULongFromStd(stdFormat);
  643.         
  644.         if( format != kODTraditionalMacText ) {
  645.             WARN("Reading IText in unknown format %ld",format);
  646.             THROW(kODErrInvalidPersistentFormat);
  647.         }
  648.         ODULong size = CMGetValueSize(cmValue) - sizeof(ODITextFormat);
  649.         name = CreateIText(size);
  650.         name->format = format;
  651.         CMReadValueData(cmValue, name->text._buffer,  sizeof(ODITextFormat), name->text._length);
  652.     } else {
  653.         name = SetITextStringLength(kODNULL,0,kODFalse);
  654.         somSelf->SetName(ev, name);
  655.     }
  656.     
  657.     ODSessionRestoreCMAllocReserve(cmContainer);
  658.         
  659.     SOM_CATCH_ALL
  660.         ODDocumentName dummy;
  661.         return dummy; // will be ignored since error set
  662.     SOM_ENDTRY
  663.     
  664.     return *name;
  665. }
  666.  
  667. //------------------------------------------------------------------------------
  668. // CMDocument: SetName
  669. //------------------------------------------------------------------------------
  670.  
  671. SOM_Scope void  SOMLINK CMDocumentSetName(CMDocument *somSelf, Environment *ev,
  672.         ODDocumentName* name)
  673. {
  674.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  675.     CMDocumentMethodDebug("CMDocument","CMDocumentSetName");
  676.  
  677.     SOM_CATCH    return;
  678.     
  679.     CMContainer    cmContainer = _fContainer->GetCMContainer(ev);
  680.     ODSessionMustHaveCMAllocReserve(cmContainer);
  681.  
  682.     CMObject    cmObject = AcquireDocumentPropertiesObject(cmContainer);
  683.     ASSERTM(cmObject, kODErrNoDocumentProperties, "No Document Properties Object.");
  684.     
  685.     CMProperty    cmProp = CMRegisterProperty(cmContainer, kODPropDocumentName);
  686.     CMType        cmType = CMRegisterType(cmContainer, kODMacIText);
  687.     CMValue        cmValue = CMUseValue(cmObject, cmProp, cmType);
  688.     if (cmValue == kODNULL) {
  689.         cmValue = CMNewValue(cmObject, cmProp, cmType);
  690.     }
  691.     ODITextFormat stdFormat = ConvertODULongToStd(name->format);
  692.     CMWriteValueData(cmValue, &stdFormat, 0, sizeof(ODITextFormat));
  693.     CMWriteValueData(cmValue, name->text._buffer,  sizeof(ODITextFormat), name->text._length);
  694.  
  695.     ODSessionRestoreCMAllocReserve(cmContainer);
  696. }
  697.  
  698. //------------------------------------------------------------------------------
  699. // CMDocument: CollapseDrafts
  700. //------------------------------------------------------------------------------
  701.  
  702. SOM_Scope ODDocument*  SOMLINK CMDocumentCollapseDrafts(CMDocument *somSelf, Environment *ev,
  703.         ODDraft* fromDraft,
  704.         ODDraft* toDraft)
  705. {
  706.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  707.     CMDocumentMethodDebug("CMDocument","CMDocumentCollapseDrafts");
  708.  
  709.     SOM_CATCH    return somSelf;
  710.  
  711.     CMDraft*        from = (CMDraft*) fromDraft;
  712.     CMDraft*        to = (CMDraft*) toDraft; ODVolatile(to);
  713.     VersionList*    versionList = kODNULL;
  714.     ODDraftID        fromID = from->GetID(ev);
  715.     ODDraftID        toID;
  716.     ODDraftID        baseID;
  717.     // ODBoolean        releaseToDraft = kODFalse; ODVolatile(releaseToDraft);
  718.     ODBoolean         revertIt = kODFalse;
  719.     
  720.     TempODDraft     tempDraft = kODNULL; // DMc - better way to release
  721.  
  722.     versionList = somSelf->TestAndGetVersionList(ev);
  723.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  724.     
  725.     TRY
  726.     
  727.         baseID = versionList->GetBaseDraftID();
  728.     
  729.         if (to == kODNULL) {
  730.             toID = versionList->GetPreviousDraftID(fromID);
  731.             to = (CMDraft*) somSelf->AcquireDraft(ev, kODDPReadOnly, toID, kODNULL, kODPosUndefined, kODFalse);
  732.             // releaseToDraft = kODTrue;
  733.             tempDraft = to; // ensure it's released
  734.         }
  735.         else {
  736.             toID = to->GetID(ev);
  737.         }
  738.         
  739.         if ((fromID == baseID) || (fromID == toID))
  740.             return somSelf;
  741.         if (versionList->IsAbove(fromID, toID) == kODFalse)
  742.             THROW(kODErrCannotCollapseDrafts);
  743.     
  744.         // from cannot have a ref count more than 1 if it is the top draft
  745.         // if from is not top draft, then we are not going to do anything to the draft
  746.         // and we need not worry about the ref count
  747.         
  748.         if (fromID == _fVersions->GetLatestDraftID())
  749.             if (from->GetRefCount(ev) > 1)
  750.                 THROW(kODErrOutstandingDraft);
  751.     
  752.         // Check for outstanding draft
  753.         
  754.         DraftListIterator draftList(_fDrafts);
  755.         draftList.Initialize();
  756.         CMDraft* draft = draftList.Last();
  757.         while (draft != kODNULL) {
  758.             ODDraftID draftID = draft->GetID(ev);
  759.             if ((versionList->IsBelow(draftID, fromID) != kODFalse) && 
  760.                 (versionList->IsAbove(draftID, toID) != kODFalse) &&
  761.                 (versionList->GetCurrentVersion(draftID) != kODTombstonedVersion))
  762.                 THROW(kODErrOutstandingDraft);
  763.             else
  764.                 draft = draftList.Previous();
  765.         }
  766.         // delete draftList;
  767.     
  768.         // Flush the from draft
  769.         
  770.         if ((from->GetPermissions(ev) == kODDPExclusiveWrite) &&
  771.             (from->NeedExternalizing(ev) != kODFalse))
  772.             THROW(kODErrNonEmptyDraft);
  773.         else if (from->IsChangedFromPrev(ev, versionList) != kODFalse)
  774.             THROW(kODErrNonEmptyDraft);
  775.         
  776.         if (from->IsNewDraft(ev) != kODFalse) {
  777.             revertIt = kODTrue;
  778. //            _fDrafts->Remove(from->GetID(ev));
  779.             ODDraftID id = from->GetID(ev);
  780.             from->Release(ev);
  781.             _fReleasedDrafts->Remove(id);
  782.             from->Abort(ev);
  783.             delete from;
  784.         }
  785.         else {
  786.             // so that the collapsed version list will be written out on close
  787.             _fContainer->SetDirtyFlag(ev, kODTrue);
  788.  
  789.             // Release the draft
  790.             
  791.             from->Release(ev);
  792.         }
  793.  
  794.         // CollapseDrafts on VersionList
  795.         
  796.         versionList->CollapseDrafts(fromID, toID);
  797.         
  798. #if !TestFlushContainer        
  799.         // Make the change persistent
  800.  
  801.         somSelf->ExternalizeVersionList(ev, kODFalse);
  802. #endif
  803.         
  804.         // If no change, then clear the dirty flag
  805.         
  806.         if (revertIt != kODFalse)
  807.             _fContainer->SetDirtyFlag(ev, kODFalse);
  808.  
  809.     CATCH_ALL
  810.     
  811.         somSelf->ReleaseVersionList(ev);
  812.         RERAISE;
  813.         
  814.     ENDTRY
  815.     
  816.     somSelf->ReleaseVersionList(ev);
  817.     
  818.     //if (releaseToDraft != kODFalse)
  819.     //    to->Release(ev);
  820.     
  821.     return somSelf;
  822. }
  823.  
  824. //------------------------------------------------------------------------------
  825. // CMDocument: AcquireDraft
  826. //------------------------------------------------------------------------------
  827.  
  828. SOM_Scope ODDraft*  SOMLINK CMDocumentAcquireDraft(CMDocument *somSelf, Environment *ev,
  829.         ODDraftPermissions perms,
  830.         ODDraftID id,
  831.         ODDraft* draft,
  832.         ODPositionCode posCode,
  833.         ODBoolean release)
  834. {
  835.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  836.     CMDocumentMethodDebug("CMDocument","CMDocumentAcquireDraft");
  837.  
  838.     SOM_CATCH    return kODNULL;
  839.  
  840. #if ODDebug_Drafts
  841.     somPrintf("&&& AcquireDraft: id %d draft %x posCode %d release %d\n", id, draft, posCode, release);
  842. #endif
  843.  
  844.     VersionList*            versionList;
  845.     ODDraft*                newDraft;
  846.  
  847.     versionList = somSelf->TestAndGetVersionList(ev);
  848.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  849.         
  850.     TRY
  851.     
  852.         newDraft = somSelf->AcquireDraftGut(ev, versionList, perms, id, (CMDraft*) draft, posCode, release);
  853.         
  854.     CATCH_ALL
  855.     
  856.         somSelf->ReleaseVersionList(ev);
  857.         RERAISE;
  858.         
  859.     ENDTRY
  860.     
  861.     somSelf->ReleaseVersionList(ev);            
  862.  
  863. #if ODDebug_Drafts
  864.     somPrintf("&&& Exiting AcquireDraft\n");
  865. #endif
  866.         
  867.     return newDraft;
  868. }
  869.  
  870. //------------------------------------------------------------------------------
  871. // CMDocument: Exists
  872. //------------------------------------------------------------------------------
  873.  
  874. SOM_Scope ODBoolean  SOMLINK CMDocumentExists(CMDocument *somSelf, Environment *ev,
  875.         ODDraftID id,
  876.         ODDraft* fromDraft,
  877.         ODPositionCode posCode)
  878. {
  879.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  880.     CMDocumentMethodDebug("CMDocument","CMDocumentExists");
  881.  
  882.     SOM_CATCH    return kODFalse;
  883.  
  884.     ODBoolean    exists = kODFalse;
  885.     
  886.     if (id != 0) {
  887.         exists = _fVersions->Exists(id);
  888.     }
  889.     else if (fromDraft != kODNULL) {
  890.     
  891.         VersionList* versionList = somSelf->TestAndGetVersionList(ev);
  892.         ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  893.         
  894.         TRY
  895.             ODDraftID    fromDraftID = fromDraft->GetID(ev);
  896.     
  897.             switch (posCode) {
  898.                 case kODPosSame:
  899.                     exists = kODTrue;
  900.                 break;
  901.                 case kODPosFirstBelow:
  902.                 case kODPosLastBelow:
  903.                     exists = versionList->PreviousDraftExists(fromDraftID);
  904.                 break;
  905.                 case kODPosFirstAbove:
  906.                 case kODPosLastAbove:
  907.                     exists = versionList->NextDraftExists(fromDraftID);
  908.                 break;
  909.                 case kODPosUndefined:
  910.                 case kODPosAll:
  911.                 case kODPosFirstSib:
  912.                 case kODPosLastSib:
  913.                 case kODPosNextSib:
  914.                 case kODPosPrevSib:
  915.                 default:
  916.                     THROW(kODErrUnsupportedPosCode);
  917.                 break;
  918.             }
  919.         CATCH_ALL
  920.             somSelf->ReleaseVersionList(ev);
  921.             RERAISE;
  922.             
  923.         ENDTRY
  924.     }
  925.     else
  926.         THROW(kODErrInsufficientInfoInParams);
  927.     
  928.     return exists;
  929. }
  930.  
  931. //------------------------------------------------------------------------------
  932. // CMDocument: AcquireBaseDraft
  933. //------------------------------------------------------------------------------
  934.  
  935. SOM_Scope ODDraft*  SOMLINK CMDocumentAcquireBaseDraft(CMDocument *somSelf, Environment *ev,
  936.         ODDraftPermissions perms)
  937. {
  938.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  939.     CMDocumentMethodDebug("CMDocument","CMDocumentAcquireBaseDraft");
  940.  
  941.     SOM_CATCH    return kODNULL;
  942.  
  943.     CMContainer    cmContainer = _fContainer->GetCMContainer(ev);
  944.     ODSessionMustHaveCMAllocReserve(cmContainer);
  945.  
  946.     ODDraftID    baseDraftID;
  947.     ODDraft*    baseDraft;
  948.     CMProperty    versionListProp;
  949.     CMObject    versionListObj;
  950.     CMType        versionListType;
  951.     CMValue        versionList;
  952.     ODSByte    bogusData[1];
  953.     
  954.     if (somSelf->GetCMVersionList(ev) == kODNULL) {
  955.         if ((versionListProp = CMRegisterProperty(cmContainer, kODPropVersionList)) == kODNULL)
  956.             THROW(kODErrBentoInvalidProperty);
  957.         if ((versionListType = CMRegisterType(cmContainer, kODVersionList)) == kODNULL)
  958.             THROW(kODErrBentoInvalidType);
  959.         if ((versionListObj = CMNewObject(cmContainer)) == kODNULL)
  960.             THROW(kODErrBentoCannotNewObject);
  961.         versionList = CMNewValue(versionListObj, versionListProp, versionListType);
  962.  
  963.         if (versionList != kODNULL)
  964.             CMWriteValueData(versionList, bogusData, 0, 0);
  965.         
  966.         _fVersions = new(somSelf->GetHeap(ev)) VersionList();
  967.         _fVersions->Initialize();
  968.         
  969.         baseDraft = somSelf->CreateDraft(ev, kODNULL, kODFalse);
  970.     }
  971.     else {
  972.         baseDraftID = _fVersions->GetBaseDraftID();
  973.         baseDraft = somSelf->AcquireDraft(ev, perms, baseDraftID, kODNULL, kODPosUndefined, kODFalse);
  974.     }
  975.     ODSessionRestoreCMAllocReserve(cmContainer);
  976.     return baseDraft;
  977. }
  978.  
  979. //------------------------------------------------------------------------------
  980. // CMDocument: CreateDraft
  981. //------------------------------------------------------------------------------
  982.  
  983. SOM_Scope ODDraft*  SOMLINK CMDocumentCreateDraft(CMDocument *somSelf, Environment *ev,
  984.         ODDraft* below,
  985.         ODBoolean releaseBelow)
  986. {
  987.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  988.     CMDocumentMethodDebug("CMDocument","CMDocumentCreateDraft");
  989.  
  990.     SOM_CATCH    return kODNULL;
  991.  
  992. #if ODDebug_Drafts
  993.     somPrintf("### Entering CreateDraft: below %x releaseBelow %d\n", below, releaseBelow);
  994.     PrintDrafts(ev, _fDrafts, "### Entering CreateDraft");
  995.     somSelf->GetVersionList(ev)->Print(">>> Entering CreateDraft");
  996. #endif
  997.     
  998.     ODDraftID                    prevDraftID;
  999.     CMDraft*                    newDraft;
  1000.     VersionList*                versionList;
  1001.     
  1002.     versionList = somSelf->TestAndGetVersionList(ev);
  1003.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  1004.         
  1005.     TRY
  1006.  
  1007.         prevDraftID = versionList->GetLatestDraftID();    
  1008.         if ((prevDraftID != 0) &&
  1009.             (below != kODNULL) &&
  1010.             (prevDraftID != below->GetID(ev)))
  1011.             THROW(kODErrInvalidBelowDraft);
  1012.     
  1013.         if (releaseBelow != kODFalse) {
  1014.             if (below != kODNULL) {
  1015.                 below->Release(ev);
  1016.             }
  1017.         }
  1018.         else {
  1019.             if ((below != kODNULL) && (below->GetPermissions(ev) == kODDPExclusiveWrite)) {
  1020.                 THROW(kODErrInvalidPermissions);
  1021.             }
  1022.         }
  1023.  
  1024.         newDraft = NewCMDraft(somSelf->GetHeap(ev));
  1025.         newDraft->InitDraft(ev, somSelf, kODNULL, kODDPExclusiveWrite);
  1026.     
  1027.         _fDrafts->Add(newDraft->GetID(ev), newDraft);
  1028.  
  1029.     CATCH_ALL
  1030.     
  1031.         somSelf->ReleaseVersionList(ev);
  1032.         RERAISE;
  1033.         
  1034.     ENDTRY
  1035.     
  1036.     somSelf->ReleaseVersionList(ev);            
  1037.     
  1038. #if ODDebug_Drafts
  1039.     PrintDrafts(ev, _fDrafts, "### Exiting CreateDraft");
  1040.     somSelf->GetVersionList(ev)->Print(">>> Exiting CreateDraft");
  1041. #endif
  1042.         
  1043.     return newDraft;
  1044. }
  1045.  
  1046. //------------------------------------------------------------------------------
  1047. // CMDocument: SaveToAPrevDraft
  1048. //------------------------------------------------------------------------------
  1049.  
  1050. SOM_Scope void  SOMLINK CMDocumentSaveToAPrevDraft(CMDocument *somSelf, Environment *ev,
  1051.         ODDraft* fromDraft,
  1052.         ODDraft* toDraft)
  1053. {
  1054.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1055.     CMDocumentMethodDebug("CMDocument","CMDocumentSaveToAPrevDraft");
  1056.  
  1057.     SOM_CATCH    return;
  1058.  
  1059.     CMDraft*        from = (CMDraft*) fromDraft;
  1060.     ODDraftID        fromID = from->GetID(ev);
  1061.     ODDraftID        toID;
  1062.     VersionList*    versionList;
  1063.     ODBoolean        notTopDraft = kODFalse;
  1064.     ODTime            now;
  1065.  
  1066.     versionList = somSelf->TestAndGetVersionList(ev);
  1067.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  1068.         
  1069.     TRY
  1070.  
  1071.         if (toDraft == kODNULL) {
  1072.             toID = _fVersions->GetPreviousDraftID(fromID);
  1073.         }
  1074.         else {
  1075.             toID = toDraft->GetID(ev);
  1076.         }
  1077.             
  1078.         if (fromID == toID)
  1079.             return;
  1080.             
  1081.         if ((_fVersions->Exists(fromID) == kODFalse) ||
  1082.             (_fVersions->Exists(toID) == kODFalse) ||
  1083.             (versionList->IsAbove(fromID, toID) == kODFalse))
  1084.             THROW(kODErrDraftDoesNotExist);
  1085.         
  1086.         // Check to see whether we have any outstanding ODDraft associated
  1087.         //    with this document.
  1088.         
  1089.         DraftListIterator draftList(_fDrafts);
  1090.         draftList.Initialize();
  1091.         
  1092.         CMDraft* draft = draftList.Last();
  1093.         while (draft != kODNULL) {
  1094.             ODDraftID    id = draft->GetID(ev);
  1095.             if ((versionList->IsBelow(id, fromID) != kODFalse) && 
  1096.                 (versionList->IsAbove(id, toID) != kODFalse) &&
  1097.                 (versionList->GetCurrentVersion(id) != kODTombstonedVersion))
  1098.                 THROW(kODErrOutstandingDraft);
  1099.             else
  1100.                 draft = draftList.Previous();
  1101.         }
  1102.         // delete draftList;
  1103.     
  1104.         // SaveToAPrevDraft on VersionList
  1105.         
  1106.         _fVersions->SaveToAPrevDraft(fromID, toID);
  1107.         
  1108.         if (fromID != _fVersions->GetLatestDraftID())
  1109.             notTopDraft = kODTrue;
  1110.  
  1111. #if !TestFlushContainer
  1112.         // Make the version list change persistent
  1113.         
  1114.         somSelf->ExternalizeVersionList(ev, kODFalse);
  1115. #endif
  1116.         
  1117.         // Write out if it is an exclusive write container
  1118.         if (notTopDraft == kODFalse)    
  1119.             from->Close(ev);
  1120.  
  1121.         CMContainer    cmContainer = _fContainer->GetCMContainer(ev);
  1122.         
  1123. #if TestFlushContainer
  1124.  
  1125.         // Make the version list change persistent
  1126.         
  1127.         somSelf->ExternalizeVersionList(ev, notTopDraft);
  1128.         
  1129.         ODSessionMustHaveCMAllocReserve(cmContainer);
  1130.         CMTakeSnapShot(cmContainer, kODFalse);
  1131. #endif
  1132.         time(&now);
  1133.         ASSERTM(sizeof(ODTime) == sizeof(time_t), kODErrAssertionFailed, "ODTime not same as time_t.");
  1134.  
  1135.         _fContainer->SetModDate(ev, now); 
  1136.  
  1137.         if (notTopDraft == kODFalse) { // if we have close it before we open it again
  1138.             from->Open(ev);
  1139.             
  1140.             from->SetChangedFromPrevFlag(ev, kODFalse);
  1141.         }        
  1142.         
  1143.         // Release to draft if necessary
  1144.         
  1145.         if (toDraft != kODNULL) {
  1146.             ((CMDraft*) toDraft)->Close(ev);
  1147.             ((CMDraft*) toDraft)->Open(ev);
  1148.         }
  1149.         ODSessionMustHaveCMAllocReserve(cmContainer);
  1150.         
  1151.     CATCH_ALL
  1152.     
  1153.         somSelf->ReleaseVersionList(ev);
  1154.         RERAISE;
  1155.         
  1156.     ENDTRY
  1157.     
  1158.     somSelf->ReleaseVersionList(ev);            
  1159. }
  1160.  
  1161. //------------------------------------------------------------------------------
  1162. // CMDocument: SetBaseDraftFromForeignDraft
  1163. //------------------------------------------------------------------------------
  1164.  
  1165. SOM_Scope void  SOMLINK CMDocumentSetBaseDraftFromForeignDraft(CMDocument *somSelf, Environment *ev,
  1166.         ODDraft* draft)
  1167. {
  1168.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1169.     CMDocumentMethodDebug("CMDocument","CMDocumentSetBaseDraftFromForeignDraft");
  1170.  
  1171.     SOM_CATCH    return;
  1172.  
  1173.     TempODDraft baseDraft = somSelf->AcquireBaseDraft(ev, kODDPExclusiveWrite);
  1174.     
  1175.     {
  1176.         TempODStorageUnit fromDraftProperties = draft->AcquireDraftProperties(ev);
  1177.         TempODStorageUnit toDraftProperties = baseDraft->AcquireDraftProperties(ev);
  1178.         
  1179.         ODDraftKey key = draft->BeginClone(ev, baseDraft, kODNULL, kODCloneAll); 
  1180.         TRY
  1181.             draft->Clone(ev, key, fromDraftProperties->GetID(ev), toDraftProperties->GetID(ev), kODNULL);
  1182.             draft->EndClone(ev, key );
  1183.         CATCH_ALL
  1184.             draft->AbortClone(ev, key);
  1185.         ENDTRY
  1186.         
  1187.     }
  1188.     baseDraft->Externalize(ev);
  1189. }
  1190.  
  1191. //------------------------------------------------------------------------------
  1192. // CMDocument: InitDocument
  1193. //------------------------------------------------------------------------------
  1194.  
  1195. SOM_Scope void  SOMLINK CMDocumentInitDocument(CMDocument *somSelf, Environment *ev,
  1196.         ODContainer* container,
  1197.         ODDocumentID id)
  1198. {
  1199.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1200.     CMDocumentMethodDebug("CMDocument","CMDocumentInitDocument");
  1201.     
  1202.     SOM_TRY
  1203.         
  1204.     /* Moved from somInit. SOM itself sets fields to zero
  1205.     _fContainer = (ODBentoContainer*) kODNULL;
  1206.     _fID = 0;
  1207.     _fDrafts = kODNULL;
  1208.     _fReleasedDrafts = kODNULL;
  1209.     
  1210.     _fVersions = kODNULL;
  1211.     _fVersionListSemaphore = 0;
  1212.     
  1213.     _fHeap = kDefaultHeapID;
  1214.     */
  1215.     
  1216.     somSelf->InitRefCntObject(ev);
  1217.     
  1218.     _fContainer = (ODBentoContainer*) container;
  1219.     if (_fContainer == kODNULL)
  1220.         THROW(kODErrIllegalNullContainerInput);
  1221.  
  1222.     _fID = id;
  1223.         
  1224.     _fDrafts = new(somSelf->GetHeap(ev)) DraftList;
  1225.     _fDrafts->Initialize();
  1226.     
  1227.     _fReleasedDrafts = new(somSelf->GetHeap(ev)) DraftList;
  1228.     _fReleasedDrafts->Initialize();
  1229.     
  1230.     somSelf->InternalizeVersionList(ev);
  1231.  
  1232.     if (_fVersions == kODNULL) {
  1233.     
  1234.         // If we get here, that means we have a new document.
  1235.         // A new document makes a container dirty by definition. Therefore,
  1236.         // we have to set the dirty flag.
  1237.     
  1238.         _fContainer->SetDirtyFlag(ev, kODTrue);
  1239.         
  1240.         // We are not creating a VersionList yet because the user may
  1241.         // just close the document without creating any version.
  1242.     
  1243.     }
  1244.     
  1245.     _fHeap = _fContainer->GetHeap(ev);
  1246.     
  1247.     SOM_CATCH_ALL
  1248.     SOM_ENDTRY
  1249. }
  1250.  
  1251. //------------------------------------------------------------------------------
  1252. // CMDocument: ReleaseDraft
  1253. //------------------------------------------------------------------------------
  1254.  
  1255. SOM_Scope ODDocument*  SOMLINK CMDocumentReleaseDraft(CMDocument *somSelf, Environment *ev,
  1256.         ODDraft* draftToRelease)
  1257. {
  1258.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1259.     CMDocumentMethodDebug("CMDocument","CMDocumentReleaseDraft");
  1260.  
  1261. #if ODDebug_Drafts
  1262.     somPrintf("@@@ ReleaseDraft: draft %x id %d\n", draftToRelease, draftToRelease->GetID(ev));
  1263.     PrintHeapInfo();
  1264. #endif
  1265.  
  1266.     CMDraft*        draft = (CMDraft*) draftToRelease;
  1267.     ODDraftID        draftID = draft->GetID(ev);
  1268.     
  1269.     SOM_TRY
  1270.     if ((draft = _fDrafts->Get(draftID)) != kODNULL) {
  1271.         _fDrafts->Remove(draftID);
  1272.         _fReleasedDrafts->Add(draftID, draft);
  1273.         if (draft->GetPermissions(ev) == kODDPExclusiveWrite) {
  1274.             if (draft->NeedExternalizing(ev) != kODFalse) {
  1275.                 if (draft->ChangedFromPrev(ev) != kODFalse)
  1276.                     _fContainer->SetDirtyFlag(ev, kODTrue);
  1277.                 draft->Close(ev);
  1278. #if !TestFlushContainer
  1279.                 somSelf->ExternalizeVersionList(ev, kODFalse);
  1280. #endif
  1281.             }
  1282.             else if (draft->IsNewDraft(ev) != kODFalse) {
  1283.                 if (draft->GetID(ev) == _fVersions->GetBaseDraftID()) {
  1284.                     if (draft->ChangedFromPrev(ev) != kODFalse)
  1285.                         draft->RemoveChanges(ev);
  1286.                     draft->Close(ev);
  1287. #if !TestFlushContainer
  1288.                     somSelf->ExternalizeVersionList(ev, kODFalse);
  1289. #endif
  1290.                 }
  1291.                 else
  1292.                     draft->Abort(ev);
  1293.             }
  1294.             else
  1295.                 draft->Abort(ev);
  1296.         }
  1297.         else
  1298.             draft->Close(ev);
  1299.     }
  1300.     else
  1301.         THROW(kODErrDraftDoesNotExist);
  1302.     SOM_CATCH_ALL
  1303.     SOM_ENDTRY
  1304.  
  1305. #if ODDebug_Drafts
  1306.     somPrintf("@@@ ReleaseDraft: Done.\n");
  1307.     PrintHeapInfo();
  1308. #endif
  1309.         
  1310.     return somSelf;
  1311. }
  1312.  
  1313. //------------------------------------------------------------------------------
  1314. // CMDocument: InternalizeVersionList
  1315. //------------------------------------------------------------------------------
  1316.  
  1317. SOM_Scope void  SOMLINK CMDocumentInternalizeVersionList(CMDocument *somSelf, Environment *ev)
  1318. {
  1319.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1320.     CMDocumentMethodDebug("CMDocument","CMDocumentInternalizeVersionList");
  1321.  
  1322.     SOM_CATCH    return;
  1323.  
  1324.     ODPtr            tmpBuffer;
  1325.     ODULong        versionListSize;
  1326.     CMValue            versionList = somSelf->GetCMVersionList(ev);
  1327.     
  1328.     if (versionList == kODNULL)
  1329.         return;
  1330.  
  1331.     CMContainer    cmContainer = _fContainer->GetCMContainer(ev);
  1332.     ODSessionMustHaveCMAllocReserve(cmContainer);
  1333.  
  1334.     versionListSize = CMGetValueSize(versionList);
  1335.     
  1336.     tmpBuffer = ODNewPtr(versionListSize, somSelf->GetHeap(ev));
  1337.     
  1338.     CMReadValueData(versionList, tmpBuffer, 0, versionListSize);
  1339.     
  1340.     if (_fVersions == kODNULL) {
  1341.         _fVersions = new(somSelf->GetHeap(ev)) VersionList;
  1342.         _fVersions->Initialize(tmpBuffer, versionListSize);
  1343.     }
  1344.     else {
  1345.         _fVersions->Reinitialize(tmpBuffer, versionListSize);
  1346.     }
  1347.     
  1348.     ODDisposePtr(tmpBuffer);
  1349.  
  1350.     ODSessionRestoreCMAllocReserve(cmContainer);
  1351.     
  1352. #if ODDebug_Drafts
  1353.     _fVersions->Print("Internalized VersionList");
  1354. #endif
  1355. }
  1356.  
  1357. //------------------------------------------------------------------------------
  1358. // CMDocument: ExternalizeVersionList
  1359. //------------------------------------------------------------------------------
  1360.  
  1361. SOM_Scope void  SOMLINK CMDocumentExternalizeVersionList(CMDocument *somSelf, Environment *ev, ODBoolean ignoreTopDraft)
  1362. {
  1363.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1364.     CMDocumentMethodDebug("CMDocument","CMDocumentExternalizeVersionList");
  1365.  
  1366.     SOM_CATCH    return;
  1367.  
  1368.     ODPtr            tmpBuffer;
  1369.     ODULong        tmpBufferSize;
  1370.     CMValue            versionList = somSelf->GetCMVersionList(ev);
  1371.  
  1372.     if (versionList == kODNULL)
  1373.         THROW(kODErrNoVersionList);
  1374.  
  1375.     if (_fVersions != kODNULL) {
  1376.         CMContainer    cmContainer = _fContainer->GetCMContainer(ev);
  1377.         ODSessionMustHaveCMAllocReserve(cmContainer);
  1378.  
  1379. #if ODDebug_Drafts
  1380.     _fVersions->Print("Externalizing VersionList");
  1381. #endif
  1382.         CMSize oldSize = CMGetValueSize(versionList);
  1383.  
  1384.         _fVersions->ExportTo(&tmpBuffer, &tmpBufferSize, ignoreTopDraft);
  1385.         
  1386.         CMWriteValueData(versionList, tmpBuffer, 0, tmpBufferSize);
  1387.         
  1388.         if (oldSize > tmpBufferSize)
  1389.             CMDeleteValueData(versionList, tmpBufferSize, oldSize - tmpBufferSize);
  1390.         
  1391.         ODDisposePtr(tmpBuffer);
  1392.         ODSessionRestoreCMAllocReserve(cmContainer);
  1393.         
  1394.     }
  1395. }
  1396.  
  1397. //------------------------------------------------------------------------------
  1398. // CMDocument: Reopen
  1399. //------------------------------------------------------------------------------
  1400.  
  1401. SOM_Scope void  SOMLINK CMDocumentReopen(CMDocument *somSelf, Environment *ev)
  1402. {
  1403.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1404.     CMDocumentMethodDebug("CMDocument","Reopen");
  1405.  
  1406.     SOM_CATCH    return;
  1407.  
  1408.     DraftListIterator iter(_fDrafts);
  1409.     CMDraft*                draft;
  1410.  
  1411.     iter.Initialize();
  1412.     draft = iter.Last();
  1413.     while (draft != kODNULL) {
  1414.         draft->Open(ev);
  1415.         draft = iter.Previous();
  1416.     }
  1417.     // delete iter;
  1418. }
  1419.  
  1420. //------------------------------------------------------------------------------
  1421. // CMDocument: GetVersionList
  1422. //------------------------------------------------------------------------------
  1423.  
  1424. SOM_Scope VersionList*  SOMLINK CMDocumentGetVersionList(CMDocument *somSelf, Environment *ev)
  1425. {
  1426.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1427.     CMDocumentMethodDebug("CMDocument","GetVersionList");
  1428.  
  1429.     return _fVersions;
  1430. }
  1431.  
  1432. //------------------------------------------------------------------------------
  1433. // CMDocument: TestAndGetVersionList
  1434. //------------------------------------------------------------------------------
  1435.  
  1436. SOM_Scope VersionList*  SOMLINK CMDocumentTestAndGetVersionList(CMDocument *somSelf, Environment *ev)
  1437. {
  1438.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1439.     CMDocumentMethodDebug("CMDocument","TestAndGetVersionList");
  1440.  
  1441.     SOM_CATCH    return kODNULL;
  1442.  
  1443.     DisableInterrupt();
  1444.  
  1445.     if (_fVersionListSemaphore > 0) {
  1446. //        if same thread,
  1447.             _fVersionListSemaphore++;
  1448. //         else {
  1449. //            EnableInterrupt();
  1450. //            THROW(kODErrVersionListUnavailable);
  1451. //
  1452.     }
  1453.     else {
  1454. //        store the thread
  1455.         _fVersionListSemaphore++;
  1456.     }
  1457.             
  1458.     EnableInterrupt();
  1459.     
  1460.     return _fVersions;
  1461. }
  1462.  
  1463. //------------------------------------------------------------------------------
  1464. // CMDocument: ReleaseVersionList
  1465. //------------------------------------------------------------------------------
  1466.  
  1467. SOM_Scope void  SOMLINK CMDocumentReleaseVersionList(CMDocument *somSelf, Environment *ev)
  1468. {
  1469.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1470.     CMDocumentMethodDebug("CMDocument","ReleaseVersionList");
  1471.  
  1472.     SOM_CATCH    return;
  1473.  
  1474.     DisableInterrupt();
  1475.     
  1476.     if (_fVersionListSemaphore > 0) {
  1477. //        if (same thread) {
  1478.             --_fVersionListSemaphore;
  1479.             EnableInterrupt();    
  1480. //        }
  1481. //        else {
  1482. //            EnableInterrupt();
  1483. //            THROW(kODErrVersionListUnavailable);
  1484. //        }
  1485.     }
  1486.     else {
  1487.         EnableInterrupt();    
  1488.         THROW(kODErrSemaphoreReleased);
  1489.     }
  1490. }
  1491.  
  1492. //------------------------------------------------------------------------------
  1493. // CMDocument: GetHeap
  1494. //------------------------------------------------------------------------------
  1495.  
  1496. SOM_Scope ODMemoryHeapID  SOMLINK CMDocumentGetHeap(CMDocument *somSelf, Environment *ev)
  1497. {
  1498.     CMDocumentData *somThis = CMDocumentGetData(somSelf);
  1499.     CMDocumentMethodDebug("CMDocument","GetHeap");
  1500.  
  1501.     return _fHeap;
  1502. }
  1503.  
  1504. //------------------------------------------------------------------------------
  1505. // AcquireDocumentPropertiesObject
  1506. //------------------------------------------------------------------------------
  1507.  
  1508. static CMObject AcquireDocumentPropertiesObject(CMContainer container)
  1509. {
  1510.     CMObject        documentPropertiesObject;
  1511.     CMProperty        docPropertiesProp;
  1512.     CMType            docPropertiesType;
  1513.     CMValue            value;
  1514.  
  1515.     // CMContainer    cmContainer = _fContainer->GetCMContainer(ev);
  1516.     // ODSessionMustHaveCMAllocReserve(cmContainer);
  1517.     // This is a static function which is only called by functions that
  1518.     // have already called ODSessionMustHaveCMAllocReserve().
  1519.  
  1520.     if ((docPropertiesProp = CMRegisterProperty(container, kODDocumentProperties)) == kODNULL)
  1521.         THROW(kODErrBentoInvalidProperty);
  1522.     documentPropertiesObject = CMGetNextObjectWithProperty(container, kODNULL, docPropertiesProp);
  1523.     
  1524.     if (documentPropertiesObject == kODNULL) {
  1525.  
  1526.         CMContainerModeFlags    openMode;
  1527.         
  1528.         CMGetContainerInfo(container, kODNULL, kODNULL, kODNULL, kODNULL, &openMode);
  1529.         if (openMode == kCMReading)
  1530.             return kODNULL;
  1531.         
  1532.         if ((docPropertiesType = CMRegisterType(container, kODValue)) == kODNULL)
  1533.             THROW(kODErrBentoInvalidProperty);
  1534.  
  1535.         if ((documentPropertiesObject = CMNewObject(container)) == kODNULL)
  1536.             THROW(kODErrBentoCannotNewObject);
  1537.             
  1538.         if ((value = CMNewValue(documentPropertiesObject, docPropertiesProp, docPropertiesType)) == kODNULL)
  1539.             THROW(kODErrBentoCannotNewValue);
  1540.             
  1541.         CMWriteValueData(value, "", 0, 0);
  1542.     }
  1543.     // ODSessionRestoreCMAllocReserve(cmContainer);
  1544.     
  1545.     return documentPropertiesObject;
  1546. }
  1547.  
  1548. //------------------------------------------------------------------------------
  1549. // NewCMDraft
  1550. //------------------------------------------------------------------------------
  1551.  
  1552. static CMDraft* NewCMDraft(ODMemoryHeapID heapID)
  1553. {
  1554.     SOMClass*    cmDraftClass = somNewClassReference(CMDraft);
  1555.     ODULong        size = cmDraftClass->somGetInstanceSize();
  1556.     ODPtr        buffer = ODNewPtr(size, heapID);
  1557.     CMDraft*    cmDraft = (CMDraft*) cmDraftClass->somRenew(buffer);
  1558.     somReleaseClassReference ( cmDraftClass );
  1559.     
  1560.     return cmDraft;
  1561. }
  1562.  
  1563. #if ODDebug_Drafts
  1564.  
  1565. //------------------------------------------------------------------------------
  1566. // PrintDrafts
  1567. //------------------------------------------------------------------------------
  1568.  
  1569. static void PrintDrafts(Environment* ev, DraftList* drafts, char* string)
  1570. {
  1571. /*
  1572.     DraftListIterator*    draftList = new DraftListIterator(drafts);
  1573.     draftList->Initialize();
  1574.     for (CMDraft* draft = draftList->Last(); draftList->IsNotComplete(); draft = draftList->Previous()) {
  1575.         somPrintf("%s: draft %x %d refCount %d\n", string, draft, draft->GetID(ev), draft->GetRefCount(ev));
  1576.     }
  1577.     delete draftList;
  1578. */
  1579. }
  1580.  
  1581. //------------------------------------------------------------------------------
  1582. // PrintHeapInfo
  1583. //------------------------------------------------------------------------------
  1584.  
  1585. static void PrintHeapInfo()
  1586. {
  1587. /*
  1588.     MemHeap*    heapID = 0;
  1589.     const char *name;
  1590.     size_t allocated;
  1591.     size_t free;
  1592.     size_t nBlocks;
  1593.     size_t nObjects;
  1594.     MMGetHeapInfo(heapID,
  1595.                     &name,
  1596.                     &allocated,
  1597.                     &free,
  1598.                     &nBlocks,
  1599.                     &nObjects );
  1600.     somPrintf("Heap: allocated %d, free %d, nBlocks %d, nObjects %d\n", allocated, free, nBlocks, nObjects);
  1601. */
  1602. }
  1603.  
  1604.  
  1605. #endif
  1606.  
  1607.  
  1608.